//////////////////////////////////////////////////////////////////////////
//
// This file is a part of XORT project.
//
// PROJECT:         Xort compiler
// FILE:            dumper.cpp
// AUTHOR:          Vladimir Gumenuk
// DATE:            22-Mar-2013
// MODIFICATIONS:
//
//
//     Copyright(c) 2014, Vladimir Gumenuk
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification, 
//     are permitted provided that the following conditions are met :
//
//     1. Redistributions of source code must retain the above copyright notice, 
//        this list of conditions and the following disclaimer.
//     2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 
//        the following disclaimer in the documentation and / or other materials provided with the distribution.
//     3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse 
//        or promote products derived from this software without specific prior written permission.
//
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
//     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
//     THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
//     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
//     OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
//     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
//     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
//     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "xort.h"

// this module contains dumping code, used mostly to test the compiler output

// Dumps the code from symbol. It must be procedure symbol
STATIC void DumpCode( SymbolRef Sym )
{
    dword dwLine = 0;
    dword dwIP = 0;
    dword i = 1;
    dword dwPrevLine = 0;
    dword dwInstrCount = 0;
    dword dwSize = Sym.m_Code.count();
    string csLine;

    message( "    __asm {" );
    while( dwIP < dwSize )
    {
        InstructionData PTR decData = Sym.getInstructionByIndex( dwIP );

        dwInstrCount += 1;

        while( MEMBER_PTR(decData)m_strInstr.Length() < 32 ) {
            MEMBER_PTR(decData)m_strInstr.Append( ' ' );
        }

        dwLine = MEMBER_PTR(decData)m_dwLineNumber;
        csLine = lex_GetLine( dwLine );

        if( x_is_metainstruction( MEMBER_PTR(decData)m_bInstrCode ) ) {
            if( dwPrevLine != dwLine && csLine.Length() > 0 ) {
#ifdef CPP_COMPILER
                message( "%06d-[ip:%06u]:    %s    ;[%u] %s", i, dwIP, (const char*)MEMBER_PTR(decData)m_strInstr, dwLine, (const char*)csLine );
#else
                message( "%@-[ip:%@]:    %@    ;[%@] %@", i, dwIP, MEMBER_PTR(decData)m_strInstr, dwLine, csLine );
#endif
                dwPrevLine = dwLine;
                csLine.Empty();
            } else {
#ifdef CPP_COMPILER
                message( "%06d-[ip:%06u]:    %s", i, dwIP, (const char*)MEMBER_PTR(decData)m_strInstr );
#else
                message( "%@-[ip:%@]:    %@", i, dwIP, MEMBER_PTR(decData)m_strInstr );
#endif
            }
        } else {
            if( dwPrevLine != dwLine && csLine.Length() > 0 ) {
#ifdef CPP_COMPILER
                message( "%06d-[ip:%06u]:        %s    ;[%u] %s", i, dwIP, (const char*)MEMBER_PTR(decData)m_strInstr, dwLine, (const char*)csLine );
#else
                message( "%@-[ip:%@]:        %@    ;[%@] %@", i, dwIP, MEMBER_PTR(decData)m_strInstr, dwLine, csLine );
#endif
                dwPrevLine = dwLine;
                csLine.Empty();
            } else {
#ifdef CPP_COMPILER
                message( "%06d-[ip:%06u]:        %s", i, dwIP, (const char*)MEMBER_PTR(decData)m_strInstr );
#else
                message( "%@-[ip:%@]:        %@", i, dwIP, MEMBER_PTR(decData)m_strInstr );
#endif
            }
        }

        ++dwIP;
        ++i;
    }

    message( "    } //__asm {" );
}

void DumpStackTransition( SymbolRef Sym )
{
    message( "--- Stack transition" );
    Sym.m_stackMembers.reset_to_begin();

#ifdef CPP_COMPILER
    const symbolref *pSym = Sym.m_stackMembers.next();
    while( pSym ) {
        message( "        local[%d]: 0x%X %s", (*pSym)->m_iIndex, (*pSym)->m_dwType, (const char*)(*pSym)->m_csName );
        pSym = Sym.m_stackMembers.next();
    }
#else // ----------------------------------------------------- XORT compiler
    Symbol pSym = Sym.m_stackMembers.next();
    while( pSym ) {
        message( "    local[%@]: 0x%@ %@", pSym.m_iIndex, pSym.m_dwType, pSym.m_csName );
        pSym = Sym.m_stackMembers.next();
    }
#endif
    message( "--- end of stack transition" );
}

void DumpSymbol( SymbolRef Sym )
{
#ifndef CPP_COMPILER
    DbgPrint( "DumpSymbol() -> %@, members: %@, args: %@", Sym.m_csName, Sym.m_listMembers.size(), Sym.m_dwArgumentsCount );
#endif
#ifdef CPP_COMPILER
    message( "Kind: %d Name: %s Type: 0x%X Index: %d", Sym.m_SymKind, (const char*)Sym.m_csName, Sym.m_dwType, Sym.m_iIndex );
#else
    message( "Kind: %@ Name: %@ Type: 0x%@ Index: %@", Sym.m_SymKind, Sym.m_csName, Sym.m_dwType, Sym.m_iIndex );
#endif

    if( Sym.m_SymKind == sk_proc && Sym.m_arAttributes.count() > 0 )
    {
        dword i;
        for( i = 0; i < Sym.m_arAttributes.count(); ++i ) {
            AttributesRef attr = Sym.m_arAttributes.get( i );
#ifdef CPP_COMPILER
            message( "    attr: %d - '%s'", attr->dwAttrCode, (const char*)attr->csAttrValue );
#else
            message( "    attr: %@ - '%@'", attr.dwAttrCode, attr.csAttrValue );
#endif
        }
    }

    if( Sym.m_listMembers.size() > 0 )
    {
        string pszOpen = Sym.m_SymKind == sk_obj ? "{" : "(";
        string pszClose = Sym.m_SymKind == sk_obj ? "}" : ")";

        message( pszOpen );
        DumpSymbolTable( Sym.m_listMembers );
        message( pszClose );
    }

    if( Sym.m_SymKind == sk_proc && Sym.m_Code.count() > 0 )
    {
        DumpCode( Sym );

        if( Sym.m_stackMembers.size() > 0 )
        {
            DumpStackTransition( Sym );
        }
    }
}

void DumpSymbolTable( SYMBOLLIST symList )
{
    symList.reset_to_end();
#ifdef CPP_COMPILER
    const symbolref *pSym = symList.prev();
    while( pSym ) {
        DumpSymbol( **pSym );
        pSym = symList.prev();
    }
#else
    Symbol pSym = symList.prev();
    while( pSym ) {
        DumpSymbol( pSym );
        pSym = symList.prev();
    }
#endif
}
